import random
import re

import logging
from django.conf import settings
from django.contrib.auth.hashers import make_password
from django.http import HttpResponse
from django.shortcuts import render
from django_redis import get_redis_connection
from itsdangerous import BadData
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.mixins import CreateModelMixin,RetrieveModelMixin,UpdateModelMixin
from rest_framework.viewsets import ViewSet, GenericViewSet

from goods.models import SKU
from goods.serializers import SKUSerializer
from meiduo_mall.utils.captcha.captcha import Captcha
from users import constants
from users.serializers import UserSerializers, UserDetailSerializer, EmailSerializer, AddressSerializer,AddressTitleSerializer, BrowseHisorySerializer, ChangPasswordSerializer, \
    ForgetPasswordSerializer
from users.models import User
from rest_framework.permissions import IsAuthenticated
from meiduo_mall.utils.captcha import captcha
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer

# Create your views here.

# 登录
# POST /authorizations/
# class UserAuthorizeView(APIView):
#     def post(self, request):
#         """
#         用户登录：
#         １.获取参数username和password并进行校验
#         2.生成jwt token保存登录用户身份信息
#         3.返回响应,登录成功
#         """






# 忘记密码-第二步表单提交-验证手机号
# GET /accounts/(?P<username>\w{5,20})/password/token/
class SecondSubmitView(APIView):
    def get(self, request, username):
        """
        表单提交
        0.获取用户对象,找出手机号
        1.从redis获取到前端的验证码,进行验证
        2.返回响应
        """

        # 0.获取用户对象,找出手机号
        if re.match('^1[3-9]\d{9}$', username):
            # 帐号为手机号
            user = User.objects.get(mobile=username)
        else:
            # 帐号为用户名
            user = User.objects.get(username=username)

        # 1.从redis获取到前端的验证码,进行验证
        sms_code = request.query_params['sms_code']

        # 获取redis链接,取出验证码
        redis_conn = get_redis_connection('verify_codes')
        true_sms_code = redis_conn.get('sms_%s' % user.mobile)

        # 验证码进行比较
        if sms_code != true_sms_code.decode():
            return Response({'message': '验证码错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 2.加密用户token
        # TJWSSerializer(秘钥, 有效期秒)
        serializer = TJWSSerializer(secret_key=settings.SECRET_KEY, expires_in=constants.VERIFY_EMAIL_TOKEN_EXPIRES)

        user_info = {
            "username": user.username,
        }

        # 对用户信息进行加密
        token = serializer.dumps(user_info).decode()  # bytes->str

        data = {
            "message":"OK",
            "user_id":user.id,
            "access_token":token
        }

        # 3.返回响应
        return Response(data)


# 忘记密码-第二步表单提交-发送短信验证码
# GET /sms_codes/
class SmsSendView(APIView):
    def get(self, request):
        """
        发送短信
        1.解析出前端地址中的token,进行解密
        2.对解密后的手机号,进行异步发短信
        3.返回响应
        """
        # 1.解析出前端地址中的token,进行解密
        access_token = request.query_params['access_token']

        serializer = TJWSSerializer(secret_key=settings.SECRET_KEY)

        try:
            data = serializer.loads(access_token)
        except BadData:
            # 解密失败
            return Response({"message":"解密失败"},status=status.HTTP_404_NOT_FOUND)
        else:
            # 解密成功
            user_id = data.get('id')
            mobile = data.get('mobile')

        # 2.对解密后的手机号,进行异步发短信
        logger = logging.getLogger('django')
        sms_code = "%06d" % random.randint(0, 999999)
        logger.info('短信验证码为:　%s' % sms_code)

        redis_conn = get_redis_connection('verify_codes')

        redis_conn.setex("sms_%s" % mobile, 300, sms_code)

        # 3.返回响应
        return Response({"message":"OK"})


# # 忘记密码-第一步表单提交
# # GET /accounts/(?P<username>\w{5,20})/sms/token/
# class ImageFirstView(APIView):
#
#     def get(self, resquest, username):
#         """
#         手机号,图片验证码第一步
#         1.获取参数,校验
#         2.返回响应,手机号和状态
#         """
#         # print(resquest.query_params)
#         # 1.获取参数,判断用户是否存在
#         if re.match('^1[3-9]\d{9}$', username):
#             # 帐号为手机号
#             user = User.objects.get(mobile=username)
#         else:
#             # 帐号为用户名
#             user = User.objects.get(username=username)
#
#         if not user:
#             return Response({'message': '用户不存在'}, status=status.HTTP_404_NOT_FOUND)
#
#         # 2.判断验证码是否正确
#         # 获取redis链接
#         redis_conn = get_redis_connection('imagecode')
#         image_code_id = resquest.query_params['image_code_id']
#         image_code = resquest.query_params['text']
#
#         # 判断验证码是否正确
#         redis_image_code = redis_conn.get('image_code:%s' % image_code_id)
#         if redis_image_code.decode().lower() != image_code:
#             return Response({'message': '短信验证码不正确'}, status=status.HTTP_400_BAD_REQUEST)
#
#
#         # 3.加密手机号
#         list = user.mobile[3:7]
#         newphone = user.mobile.replace(list, '****')
#
#
#         # 4.加密用户token
#         # TJWSSerializer(秘钥, 有效期秒)
#         serializer = TJWSSerializer(secret_key=settings.SECRET_KEY, expires_in=constants.VERIFY_EMAIL_TOKEN_EXPIRES)
#
#         user_info = {
#             "id":user.id,
#             "mobile":user.mobile
#         }
#
#         # 对用户信息进行加密
#         token = serializer.dumps(user_info).decode()  # bytes->str
#
#
#         data = {
#             "message":"OK",
#             "mobile":newphone,
#             "access_token":token
#         }
#
#         # 5.返回响应,手机号和状态
#         return Response(data)


# 忘记密码-第一步表单提交
# GET /accounts/(?P<username>\w{5,20})/sms/token/
class ImageFirstView(GenericAPIView):
    serializer_class = ForgetPasswordSerializer

    def get(self, resquest, username):
        """
        手机号,图片验证码第一步
        1.获取参数,校验
        2.返回响应,手机号和状态
        """

        text = resquest.query_params['text']
        image_code_id = resquest.query_params['image_code_id']

        u_dict = {
            "username":username,
            "text":text,
            "image_code_id":image_code_id,
            "access_token":0,
            "mobile":0
        }


        # username : qingqiucanshu
        # text image: ?
        # 1.获取参数, 校验
        serilaizer = self.get_serializer(data=u_dict)
        serilaizer.is_valid(raise_exception=True)

        # print(serilaizer.data)


        # 2.返回响应,手机号和状态
        return Response(serilaizer.data)



# 忘记密码-图片验证码实现
# /image_codes/image_code_id/
class ImageCodesView(APIView):
    def get(self, resquest, image_code_id):
        """
        实现图片验证码
        1.根据generate_captcha获取图片验证码,验证码值,图片(二进制)
        2.将图片验证码保存在redis中
        3.返回图片
        """
        # 1.根据generate_captcha获取图片验证码,验证码值,图片(二进制)
        name,text,image_data = Captcha.instance().generate_captcha()

        # 2.将图片验证码保存在redis中
        # 获取redis链接
        redis_conn = get_redis_connection('imagecode')

        redis_conn.setex('image_code:%s'%image_code_id, 60, text)

        # 3.返回图片
        return HttpResponse(image_data)




# 用户中心-修改密码
# /users/(?P<user_id>\d+)/password/
class ChangPasswordView(GenericAPIView):
    serializer_class = ChangPasswordSerializer

    def put(self, resquest,user_id):
        """
        修改密码
        0.根据用户id获取用户数据
        1.获取参数,进行校验（两次密码是否一致,旧密码是否正确）
        2.修改用户密码，并保存
        3.返回响应
        """
        # 1.获取参数,进行校验（两次密码是否一致,旧密码是否正确）
        serializer = self.get_serializer(data=resquest.data)
        serializer.is_valid(raise_exception=True)

        # 2.修改用户密码，并保存
        serializer.save()

        # 3.返回响应
        return Response({"message":"OK"})

    def post(self, request, user_id):
        # 忘记密码-第三步表单提交-修改密码
        """
        重置新密码
        1.取出用户名,获取用户对象
        2.修改用户对象中的密码
        3.保存数据
        4.反回响应
        """
        # 1.取出用户名,获取用户对象
        serializer = TJWSSerializer(secret_key=settings.SECRET_KEY)

        try:
            data = serializer.loads(request.data['access_token'])
        except BadData:
            # 解密失败
            return Response({"message": "解密失败"}, status=status.HTTP_404_NOT_FOUND)
        else:
            # 解密成功
            username = data.get('username')

        user = User.objects.get(username=username)

        # 2.修改用户对象中的密码

        user.password= make_password(request.data['password'])
        # 3.保存数据
        user.save()

        # 4.反回响应
        return Response({"message":"OK"})



# 用户中心-浏览记录添加
# POST /browse_histories/
class BrowseHisoryView(CreateAPIView):
    # 访问权限设置,IsAuthenticated：只有认证过的用户才可以访问
    permission_classes = [IsAuthenticated]
    serializer_class = BrowseHisorySerializer

    # def post(self, request):
    #     """
    #     登录浏览记录的添加
    #     1.获取sku_id并进行校验(stu_id必传，sku_id是否存在)
    #     2.在redis中存储登录用户浏览器的记录
    #     3.返回应答,浏览记录添成功
    #     """
    #     # 1.获取sku_id并进行校验(stu_id必传，sku_id是否存在)
    #     serilaizer = self.get_serializer(data=request.data)
    #     serilaizer.is_valid(raise_exception=True)
    #
    #     # 2.在redis中存储登录用户浏览器的记录(create)
    #     serilaizer.save()
    #
    #     # 3.返回应答,浏览记录添成功
    #     return Response(serilaizer.data, status.HTTP_201_CREATED)

    def get(self, resquest):
        """
        登录浏览记录获取
        1.从redis中获取用户浏览的商品id
        2.根据sku_id获取对应商品数据
        3.将商品的数据序列化返回
        """
        # 获取链接对象
        redis_conn = get_redis_connection('histories')

        # 拼接key
        history_key = 'history_%s' % resquest.user.id

        # 1.从redis中获取用户浏览的商品id
        # [b'<sku_id>',b'<sku_id>']
        sku_ids = redis_conn.lrange(history_key, 0, -1)
        # print(sku_ids)

        # 2.根据sku_id获取对应商品数据
        skus = []
        for sku_id in sku_ids:
            # SKU.objects.get 内会自动转换
            sku = SKU.objects.get(id=sku_id)
            skus.append(sku)

        # print(skus)
        # 3.将商品的数据序列化返回
        serilaizer = SKUSerializer(skus, many=True)
        return Response(serilaizer.data)


# 地址管理-地址新增
# POST /addresses/
class AddressViewSet(CreateModelMixin, UpdateModelMixin,GenericViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = AddressSerializer

    def get_queryset(self):
        return self.request.user.addresses.filter(is_deleted=False)

    # POST /addresses/
    def create(self, request):
        """
        登录地址新增
        request.user:获取登录用户对象
        0.判断用户地址数量是否超过数量上限
        1.获取参数并进行校验(参数完整性,手机号格式,邮箱格式)
        2.创建并保存新增地址数据
        3.将新增地址数据序列化并返回
        """
        # 0.判断用户地址数量是否超过数量上限
        count = request.user.addresses.filter(is_deleted=False).count()

        if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
            return Response({"message":"地址数量超过上限"}, status=status.HTTP_400_BAD_REQUEST)

        # # 1.获取参数并进行校验(参数完整性,手机号格式,邮箱格式)
        # serializer = self.get_serializer(data=request.data)
        # serializer.is_valid(raise_exception=True)
        #
        # # 2.创建并保存新增地址数据(create)
        # serializer.save()
        #
        # # 3.将新增地址数据序列化并返回
        # return Response(serializer.data, status=status.HTTP_201_CREATED)

        # 调用CreateModelMixin中create方法
        return super().create(request)

    # GET /addresses/
    def list(self, request):
        """
        获取登录用户的数据
        # 1.获取登录用户的数据
        # 2.将地址数据序列化并返回
        """
        # 1.获取登录用户的数据
        addresses = self.get_queryset()

        # 2.将地址数据序列化并返回
        serializer = self.get_serializer(addresses, many=True)

        user = request.user
        return Response({
            'user_id': user.id,
            'default_address_id': user.default_address_id,
            'limit': constants.USER_ADDRESS_COUNTS_LIMIT,
            'addresses': serializer.data,
        })

    # DELETE /addresses/(?P<pk>\d+)/
    def destroy(self, request, pk):
        """
        删除(逻辑删除)登录用户的指定地址:
        1.根据pk获取指定的地址数据
        2.将地址的is_deleted设置为True
        3.返回应答
        """
        # 1.根据pk获取指定的地址数据
        address = self.get_object()

        # 2.将地址的is_deleted设置为True
        address.is_deleted = True
        address.save()

        # 3.返回应答
        return Response(status=status.HTTP_204_NO_CONTENT)

    # # PUT /address/(?P<pk>\d+)/
    # def update(self, request, pk):
    #     """
    #     修改登录用户指定地址
    #     1.根据pk获取指定的地址数据
    #     2.获取参数并进行校验
    #     3.修改指定地址数据
    #     4.返回修改地址序列化数据
    #     """
    #     # 1.根据pk获取指定的地址数据
    #     address = self.get_object()
    #
    #     # 2.获取参数并进行校验
    #     serializer = self.get_serializer_class(address, data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #
    #     # 3.修改指定地址数据(update)
    #     serializer.save()
    #
    #     # 4.返回修改地址序列化数据
    #     return Response(serializer.data)


    # PUT /addresses/(?P<pk>\d+)/status/
    # detail：是否需要提取url的参数,需要等于Ｔru
    @action(methods=['put'], detail=True)
    def status(self, request, pk):
        """
        设置登录用户的默认地址
        1.根据pk去查询指定的地址
        2.设置登录用户的默认地址
        3.返回应答,设置成功
        """
        # 1.根据pk去查询指定的地址
        address = self.get_object()

        # 2.设置登录用户的默认地址
        # request.user.default_address = address
        request.user.default_address_id = address.id
        request.user.save()

        # 3.返回应答,设置成功
        return Response({'message':'OK'})

    # PUT /addresses/(?P<pk>\d+)/title/
    @action(methods=['put'], detail=True)
    def title(self, request, pk):
        """
        修改指定地址标题
        1.根据pk去查询指定的地址
        2.获取title参数并校验(title必传)
        3.修改指定地址的标题并更新数据库
        4.返回应答，设置标题成功
        """
        # 1.根据pk去查询指定的地址
        address = self.get_object()

        # 2.获取title参数并校验(title必传)
        serializer = AddressTitleSerializer(address, data=request.data)
        serializer.is_valid(raise_exception=True)

        # 3.修改指定地址的标题并更新数据库(update)
        serializer.save()

        # 4.返回应答，设置标题成功
        return Response(serializer.data)


# 用户中心-邮箱判断验证
# PUT emails/verification/?token=<加密用户信息>
class EmailVerifyView(APIView):
    def put(self, request):
        """
        用户邮箱验证
        1.获取token并进行校验(token必传,token是否有效)
        2.设置对应用户的邮箱验证标记email_active为True
        3.返回应答,验证成功
        """
        # 1.获取token并进行校验(token必传,token是否有效
        token = request.query_params.get('token')

        if not token:
            return Response({'message': '缺少token'}, status=status.HTTP_400_BAD_REQUEST)

        # 对token进行解密
        user = User.check_verify_email_token(token)


        if user is None:
            return Response({'message': '链接信息无效'}, status=status.HTTP_400_BAD_REQUEST)

        # 2.设置对应用户的邮箱验证标记email_active为True
        user.email_active = True
        user.save()

        # 3.返回应答,验证成功
        return Response({'message': 'OK'})


# 用户中心－邮箱验证
# PUT /email/
class EmailView(UpdateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = EmailSerializer

    def get_object(self):
        """返回登录用户对象"""
        return self.request.user

    # def put(self, request):
    #     """
    #     登陆用户邮箱
    #     1.获取参数并进行校验(email必传,email格式)
    #     2.设置登陆用户的邮箱
    #     3.返回应答,邮箱设置成功
    #     """
    #     # 获取登录用户
    #     user = self.get_object()
    #
    #     # 1.获取参数并进行校验(email必传,email格式)
    #     serializer = self.get_serializer(user, data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #
    #     # 2.设置登陆用户的邮箱并且发送用户验证邮件(update)
    #     serializer.save()
    #
    #     # 3.返回应答,邮箱设置成功
    #     return Response(serializer.data)


# 用户中心
# GET /user/
class UserDetailView(RetrieveAPIView):
    # 访问权限设置,IsAuthenticated：只有认证过的用户才可以访问
    permission_classes = [IsAuthenticated]
    serializer_class = UserDetailSerializer


    def get_object(self):
        """重写GenericAPIView中的方法,返回登录用户对象"""
        # self.requset: request请求对象
        return self.request.user



    # def get(self, request):
    #     """
    #     request.user
    #     获取登陆用户基本信息
    #     1.获取登录用户
    #     2.将登陆用户序列化并返回
    #     """
    #     # 1.获取登录用户
    #     user = self.get_object()
    #
    #     # 2.将登陆用户序列化并返回
    #     serializer = self.get_serializer(user)
    #     return Response(serializer.data)


# 注册
# POST /users/
class UserView(CreateAPIView):
    # 指定序列化器类
    serializer_class = UserSerializers

    # def post(self, request):
    #     """
    #     注册用户信息的保存
    #     # 1.获取参数并进行校验(参数完整性,用户名不能全不为数字,是否同意协议,手机号格式,手机号是否存在,两次密码是否一致,短信验证码是否正确)
    #     # 2.创建新用户,保存在数据库
    #     # 3.将新用户序列化并返回
    #     """
    #     # 1.获取参数并进行校验(参数完整性,是否同意协议,手机号格式,手机号是否存在,两次密码是否一致,短信验证码是否正确)
    #     serializer = self.get_serializer(data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #
    #     # 2.创建新用户,保存在数据库(create)
    #     serializer.save()
    #
    #     # 3.将新用户序列化并返回
    #     return Response(serializer.data, status=status.HTTP_201_CREATED)


# 用户名
# GET /usernames/(?P<username>\w{5, 20})/count/
class UsernameCountView(APIView):
    def get(self, request, username):
        """
        根据用户名数量
        1.根据用户名查询数据库, 获取查询结果数量
        2.返回用户数量
        """
        # 1.根据用户名查询数据库, 获取查询结果数量
        count = User.objects.filter(username=username).count()

        # 2.返回用户数量
        res_data = {
            'username':username,
            'count':count
        }
        return Response(res_data)


# 手机号
# GET /mobiles/(?P<mobile>1[3-9]\d{9})/count/
class MobileCountView(APIView):
    def get(self, request, mobile):
        """
        根据用户名数量
        1. 根据用户名查询数据库, 获取查询结果数量
        2. 返回用户数量
        """
        # 1.根据用户名查询数据库, 获取查询结果数量
        count = User.objects.filter(mobile=mobile).count()

        # 2.返回用户数量
        res_data = {
            'mobile': mobile,
            'count': count
        }
        return Response(res_data)



